package com.example.readerapp.myandserver.util;

import com.example.readerapp.myandserver.mybookconfig.BookInfoTable;
import com.example.readerapp.myandserver.mybookconfig.MyBookConfig;
import com.itextpdf.kernel.geom.LineSegment;
import com.itextpdf.kernel.geom.Rectangle;
import com.itextpdf.kernel.geom.Vector;
import com.itextpdf.kernel.pdf.PdfDocument;
import com.itextpdf.kernel.pdf.PdfReader;
import com.itextpdf.kernel.pdf.canvas.parser.EventType;
import com.itextpdf.kernel.pdf.canvas.parser.PdfTextExtractor;
import com.itextpdf.kernel.pdf.canvas.parser.data.IEventData;
import com.itextpdf.kernel.pdf.canvas.parser.data.TextRenderInfo;
import com.itextpdf.kernel.pdf.canvas.parser.listener.*;
import com.itextpdf.kernel.pdf.canvas.parser.filter.TextRegionEventFilter;
import com.itextpdf.kernel.pdf.canvas.parser.listener.FilteredTextEventListener;

import java.io.File;
import java.io.FileWriter;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class FormatBookUtil
{
    static String bookPath="C:\\Users\\ASUS\\Desktop\\1376_shadow-slave_未完结.pdf";
    static String zipPath="C:\\Users\\ASUS\\Desktop\\1376_shadow-slave_未完结.zip";
    static String tempFile="C:\\Users\\ASUS\\Desktop\\temp\\";
    static String unzipPath="D:\\JAVA代码\\UtilDEV\\src\\main\\resources\\unzip\\";

    public static void main(String[] a)
    {
        try
        {
         //   createFormatBookForPurifyWordPdf(bookPath,zipPath,tempFile);
        }
        catch (Exception e)
        {
            e.printStackTrace();
        }
    }

    /**
     * 将pdf格式的电子书切分并转换为HTML，创建一个config.txt文件保存电子书其他信息,然后压缩他们，
     * @param pdfFilePath pdf文件路径 参考值："C:\\Users\\ASUS\\Desktop\\Grandmaster of Demonic Cultivation(魔道祖师).pdf";
     * @param tempFileSavePath 临时文件路径 参考值："D:\\JAVA代码\\UtilDEV\\src\\main\\resources\\temp\\";
     * @param zipFileSavePath zip文件保存路径 参考值："D:\\JAVA代码\\UtilDEV\\src\\main\\resources\\test.zip";
     * */
    public static void createFormatBook(String pdfFilePath,String zipFileSavePath, String tempFileSavePath) throws Exception
    {

        System.out.println("文件--begin");
        //临时文件保存目录
        File tempDir=new File(tempFileSavePath);
        tempDir.mkdir();
        System.out.println("文件--dede");

        //临时切分的pdf文件
        String splitPdfPath=tempFileSavePath+"pdf/";//不要用pdf\\,安卓平台不支持
        new File(splitPdfPath).mkdir();
        //转换的html文件
        String htmlPath=tempFileSavePath+"html/";
        new File(htmlPath).mkdir();
        //配置文件
        String config=htmlPath+"config.txt";
        System.out.println("文件——开始切分pdf");
        PdfUtil.splitPdf(pdfFilePath, splitPdfPath,1);
        System.out.println("文件--结束切分");
        //开始pdf转html
        File file=new File(splitPdfPath);
        File[] list=file.listFiles();
        //PdfUtil.extractText(list[0].getAbsolutePath(),"C:\\Users\\ASUS\\Desktop\\extra.txt");
        if(list!=null)
        {
            try
            {
                for (File f : list)
                {
                    String name = f.getName().replaceAll("\\.pdf", "");
                    String path = f.getAbsolutePath();
                    PdfReader pdfReader = new PdfReader(path);
                    //String[] extraText=PdfUtil.extractTextFromPdf(PdfUtil.extractTextFromWebNovelSave,path,1).split("\n");
                    //这个文字提取应该是基于ocr的，容易出现重复、遗漏
                    String[] extraText = PdfUtil.extractTextFromPdf(PdfUtil.extractTextCommon, path, 1).split("\n");
                    pdfReader.close();//记得关闭
                    String html = "";
                    for (int i = 0; i < extraText.length; i++)
                    {
                        extraText[i] = "<p>" + extraText[i] + "</p>";
                        html = html + extraText[i] + "\n";
                    }
                    FileUtil.writerText(htmlPath + name + ".html", html, true);
                    f.delete();//不知道为啥，不删除的话Android会出问题
                    System.out.println("文件--" + f.getAbsolutePath() + "转换为html结束");
                }
            }catch (Exception e)
            {
                System.out.println("文件--异常"+e.getMessage());
            }
        }

        //创建配置文件 */
        new File(config).createNewFile();
        FileUtil.writerText(config,"\n总页数:"+list.length,true);
        FileUtil.writerText(config,"\n当前页:"+1,true);
        //压缩文件
        ZipUtil.toZip(Arrays.asList(new File(htmlPath).listFiles()), new File(zipFileSavePath));
        //删除临时文件
        deleteFile(tempDir);
    }
    public static void createFormatBookForPurifyWordPdf(String pdfFilePath,String zipFileSavePath, String tempFileSavePath) throws Exception
    {
        SimpleDateFormat simpleDateFormat=new SimpleDateFormat("hh:mm:ss");
        System.out.println("开始转换："+simpleDateFormat.format(new Date()));
        File tempDir=new File(tempFileSavePath);
        //每150gehtml文件一个文件夹，防止文件夹文件过多导致速度降低
        int htmlDriNum=1;
        tempDir.mkdir();
        String htmlPath=tempFileSavePath+"html_"+htmlDriNum+"/";
        new File(htmlPath).mkdir();

        //配置文件
        String config=htmlPath+"config.txt";

        PdfDocument pdfDocument=new PdfDocument(new PdfReader(pdfFilePath));
        int numbers= pdfDocument.getNumberOfPages();
        for(int pageNum=1;pageNum<= numbers;pageNum++)
        {
            if(pageNum%150==0)
            {
                htmlDriNum++;
                htmlPath=tempFileSavePath+"html_"+htmlDriNum+"/";
                new File(htmlPath).mkdir();

            }
            float height = pdfDocument.getPage(pageNum).getPageSize().getHeight();
            float width = pdfDocument.getPage(pageNum).getPageSize().getWidth();
            Rectangle rect = new Rectangle(width, height);
            FilteredTextEventListener filterListener = new FilteredTextEventListener(new MySimpleTextExtractionStrategy(), new TextRegionEventFilter(rect));
            //FilteredTextEventListener filtered_Test=new FilteredTextEventListener(new FilteredTextEventListener(),new TextRegionEventFilter(rect));
            String extractedText = PdfTextExtractor.getTextFromPage(pdfDocument.getPage(pageNum), filterListener);
            //String extractedText = PdfTextExtractor.getTextFromPage(pdfDocument.getPage(pageNum));

            String[] extraText= extractedText.split("\n");
            extractedText="";
            for (int i=0;i<extraText.length;i++)
            {
                extractedText= extractedText+extraText[i].trim()+"\n";
            }
            extraText= splitPassage(extractedText).split("\n");
            String html = "";
            for (int i = 0; i < extraText.length; i++)
            {
                String t=extraText[i].trim();
                t = "<p>" + t + "</p>";
                html = html + t + "\n";
            }
            //可能会出现同一页重复写入两次的情况
            FileUtil.writerText(htmlPath +pageNum+ ".html", html, false);
        }
        ;
        //创建配置文件
        new File(config).createNewFile();
        FileUtil.writerText(config, "\n总页数:" + numbers, true);
        FileUtil.writerText(config, "\n当前页:" + 1, true);
        //压缩文件
        List<File> fileList=new ArrayList<>();
         File[] temp=tempDir.listFiles();
         for(int i=0;i<temp.length;i++)
         {
             File[] t2=temp[i].listFiles();
             for(int j=0;j<t2.length;j++)
             {
                 fileList.add(t2[j]);
             }

         }
        ZipUtil.toZip(fileList, new File(zipFileSavePath));
         fileList=null;
         //在这里开多线程会阻塞controller？好奇怪，只能在controller删
        //删除临时文件
       /* ExecutorService executorService= Executors.newCachedThreadPool();
        executorService.execute(new Thread(new Runnable()
        {
            @Override
            public void run()
            {

                    deleteFile(tempDir);
            }
        }));
        executorService.shutdown();*/
        pdfDocument.close();
        System.out.println("结束转换："+simpleDateFormat.format(new Date()));


    }


    /**
     * 将IText自带的SimpleTextExtractionStrategy类略做修改：
     * if (spacing > renderInfo.getSingleSpaceWidth()/2f)改为if (spacing > renderInfo.getSingleSpaceWidth()/4f)
     * 解决了部分pdf文件字符直接的空格丢失了的现象，但不保证不会出现新的问题
     *参考：https://stackoverflow.com/questions/13644419/itext-java-pdf-to-text-creation/13645183#
     *
     * */

    private static class MySimpleTextExtractionStrategy implements ITextExtractionStrategy
    {
        private Vector lastStart;
        private Vector lastEnd;

        /** used to store the resulting String. */
        private final StringBuilder result = new StringBuilder();

        @Override
        public void eventOccurred(IEventData data, EventType type) {
            if (type.equals(EventType.RENDER_TEXT)) {
                TextRenderInfo renderInfo = (TextRenderInfo)data;
                boolean firstRender = result.length() == 0;
                boolean hardReturn = false;

                LineSegment segment = renderInfo.getBaseline();
                Vector start = segment.getStartPoint();
                Vector end = segment.getEndPoint();

                if (!firstRender){
                    Vector x1 = lastStart;
                    Vector x2 = lastEnd;

                    // see http://mathworld.wolfram.com/Point-LineDistance2-Dimensional.html
                    float dist = (x2.subtract(x1)).cross((x1.subtract(start))).lengthSquared() / x2.subtract(x1).lengthSquared();

                    // we should probably base this on the current font metrics, but 1 pt seems to be sufficient for the time being
                    float sameLineThreshold = 1f;
                    if (dist > sameLineThreshold)
                        hardReturn = true;

                    // Note:  Technically, we should check both the start and end positions, in case the angle of the text changed without any displacement
                    // but this sort of thing probably doesn't happen much in reality, so we'll leave it alone for now
                }

                if (hardReturn){
                    //System.out.println("<< Hard Return >>");
                    appendTextChunk("\n");
                } else if (!firstRender){
                    // we only insert a blank space if the trailing character of the previous string wasn't a space, and the leading character of the current string isn't a space
                    if (result.charAt(result.length()-1) != ' ' && renderInfo.getText().length() > 0 && renderInfo.getText().charAt(0) != ' '){
                        float spacing = lastEnd.subtract(start).length();
                        if (spacing > renderInfo.getSingleSpaceWidth()/4f){
                            appendTextChunk(" ");
                            //System.out.println("Inserting implied space before '" + renderInfo.getText() + "'");
                        }
                    }
                } else {
                    //System.out.println("Displaying first string of content '" + text + "' :: x1 = " + x1);
                }

                //System.out.println("[" + renderInfo.getStartPoint() + "]->[" + renderInfo.getEndPoint() + "] " + renderInfo.getText());
                appendTextChunk(renderInfo.getText());

                lastStart = start;
                lastEnd = end;
            }
        }

        @Override
        public Set<EventType> getSupportedEvents() {
            return Collections.unmodifiableSet(new LinkedHashSet<>(Collections.singletonList(EventType.RENDER_TEXT)));
        }

        /**
         * Returns the result so far.
         * @return	a String with the resulting text.
         */
        @Override
        public String getResultantText() {
            return result.toString();
        }

        /**
         * Used to actually append text to the text results.  Subclasses can use this to insert
         * text that wouldn't normally be included in text parsing (e.g. result of OCR performed against
         * image content)
         * @param text the text to append to the text results accumulated so far
         */
        protected final void appendTextChunk(CharSequence text){
            result.append(text);
        }

    }
    private static String splitPassage(String text)
    {
        char[] line=text.toCharArray();
        String result="";
        for(int i=0;i<line.length;i++)
        {
            if(line[i]=='\n')
            {
                if (i-1>=0&&i+1<line.length)
                {
                    if((line[i+1]>='a'&&line[i+1]<='z')||(line[i+1]==' ')||(line[i-1]==' ')||(line[i-1]>='a'&&line[i-1]<='z')||line[i-1]==',')
                    {
                        line[i]=' ';//认为与上一行为同一段落
                    }
                }
            }
            result=result+line[i];
        }
        return result;
    }


    //读取格式化保存后的zip文件中的书籍页面
    public static String getBookPage(String bookPath,int pageNumber) throws Exception
    {
        if(pageNumber>getAllPageNumber(bookPath))
        {
            throw new StackOverflowError();
        }
        return ZipUtil.readTextFromZip(bookPath,pageNumber+".html");

    }
    /**
     * 读取格式化图书配置信息，获取总计页号
     *
     * */
    public static int getAllPageNumber(String bookPath) throws Exception
    {

       String[] content=ZipUtil.readTextFromZip(bookPath,"config.txt").split("\n");
       int all=0;
       for(int i=0;i< content.length;i++)
       {
           if(content[i].contains("总页数"))
           {
               all=Integer.parseInt(content[i].split(":")[1]);
               break;
           }
       }
       return all;
    }

    /**
     * 对于不把相关信息存在zip而是单独存在一个文件的情况
     * 读取格式化图书配置信息，获取当前阅读页号

     * @param bookName 书籍名称，带文件后缀
     *
     * */
    synchronized   public static int getCurrentPageNumber(BookInfoTable bookInfoTable,String basePath,String bookName)
    {
        consistency(bookInfoTable,basePath);

        int current=1;
        current=bookInfoTable.findCurrentPageNumberByBookName(bookName);
        return current;
    }
    /**
     * 对于不把相关信息存在zip而是单独存在一个文件的情况
     * 读取格式化图书配置信息，设置当前阅读页号
     *
     * */
    synchronized public static void setCurrentPageNumber(BookInfoTable bookInfoTable,String basePath,String bookName,int pageNumber) throws Exception
    {
        consistency(bookInfoTable,basePath);
        bookInfoTable.updateCurrentPageNumberByBookName(bookName,pageNumber);
    }
    synchronized public static void addBookConfig(BookInfoTable bookInfoTable,String basePath,String bookName,int pageNumber) throws Exception
    {

        consistency(bookInfoTable,basePath);
        bookInfoTable.insertBookInfo(bookName,pageNumber);
    }
    /**
     * 维护书籍列表和书籍配置信息的一致性
     *
     * */
    synchronized public static void consistency(BookInfoTable bookInfoTable,String basePath)
    {

        File[] books=new File(basePath).listFiles();//得实际存在哪些书籍
        for(int i=0;i<books.length;i++)
        {
            if(!bookInfoTable.findBookByBookName(books[i].getName()))//再数据库中没有找到没有找到
            {
                bookInfoTable.insertBookInfo(books[i].getName(),1);
            }
        }

/*        Map<Integer,String[]> re=bookInfoTable.queryAll();
        Set<Map.Entry<Integer,String[]>> r=re.entrySet();//得数据库

        /*清空原文件*/
      /*  try{
            bookInfoTable.deleteAll();
        }catch (Exception e){}
        boolean find=false;
        for(int i=0;i<books.length;i++)
        {
            // System.out.println(books[i].getName());
            for(Map.Entry entry:r)
            {
                String[] book= (String[]) entry.getValue();
                //返回值具体含意参考BookInfo表

                String name=book[0].replaceAll("\n","");
                String number=book[1].replaceAll("\n","");
                String bc=book[2].replaceAll("\n","");
                String fc=book[3].replaceAll("\n","");
                //库中存在此书籍信息
                if(name.equals(books[i].getName()))
                {
                    find=true;
                    bookInfoTable.insertBookInfo(name,Integer.parseInt(number),bc,fc);
                    //FormatSaveUtil.save(configPath, new String[]{name, number});
                    break;
                }
            }
            //库中没有找到此书籍信息
            if(!find)
            {
                bookInfoTable.insertBookInfo(books[i].getName(),1);
                //System.out.println("缺少："+books[i].getName());
                //FormatSaveUtil.save(configPath, new String[]{books[i].getName(),"当前页:1"});
            }
            find=false;
        }
        */

    }


   synchronized private static void deleteFile(File file){
        //判断文件不为null或文件目录存在
        if (file == null || !file.exists()){
            System.out.println("文件删除失败,请检查文件路径是否正确");
            return;
        }
        //取得这个目录下的所有子文件对象
        File[] files = file.listFiles();
        //遍历该目录下的文件对象
        for (File f: files){
            //判断子目录是否存在子目录,如果是文件则删除
            if (f.isDirectory()){
                deleteFile(f);
            }else {
                if(!f.delete())
                {
                    System.out.println("删除失败："+f.getName());
                }
            }
        }
        //删除空文件夹  for循环已经把上一层节点的目录清空。
        file.delete();
    }

}
